package com.business.redis;

import com.business.redis.utils.RedisUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.UUID;

/**
 * redis 锁类
 * 拥有获得锁和解锁方法
 */
public class RedisLock {

    private final Logger logger = LoggerFactory.getLogger(RedisLock.class);

    private String lockId;//锁id
    private String lockKey;//锁住的redisKey

    private long waitTime = 60 * 1000;//等待时间
    private long expireTime = 60 * 1000; //锁过期时间
    private boolean success ;//判断是否已经获取了锁

    public RedisLock(String lockKey){
        this.lockId = UUID.randomUUID().toString();
        this.lockKey = "Lock:"+lockKey;
    }

    public RedisLock(String lockKey,long expireTime,long waitTime){
        this(lockKey);
        this.expireTime = expireTime;
        this.waitTime = waitTime;
    }

    public static RedisLock build(String lockKey){
        return  new RedisLock(lockKey);
    }

    public static RedisLock build(String lockKey,long expireTime,long waitTime){
        return  new RedisLock(lockKey,expireTime,waitTime);
    }

    /**
     * 获取锁
     */
    public synchronized void lock() {
        if(this.success){
            return;
        }
        int alreadyWaitTime = 0;
        while (waitTime > alreadyWaitTime) {
            //如果不存在就设置锁值
            boolean success =  RedisUtil.setIfAbsent(lockKey,lockId,expireTime);
            if (success) {
                this.success = true;
                return;
            } else {
                try {
                    Thread.sleep(100);//睡眠时间
                } catch (InterruptedException e) {
                    logger.warn("获取锁失败,lockKey:"+this.lockKey+","+e.getMessage(), e);
                    throw new RuntimeException("获取锁失败,lockKey:"+this.lockKey+","+e.getMessage());
                }
            }
            alreadyWaitTime += 100;
        }
        throw new RuntimeException("获取锁失败,lockKey:"+this.lockKey);
    }

    /**
     * 尝试获取锁
     * @return
     */
    public synchronized boolean tryLock() {
        if (this.success){
            return  true;
        }
        //如果存在key 表示 无法获取锁
        boolean success =  RedisUtil.setIfAbsent(lockKey,lockId,expireTime);
        if (success) {
            this.success = true;
            return true;
        }
        return false;
    }

    /**
     * 释放锁
     */
    public synchronized boolean unlock() {
        if(this.success && this.lockId.equals(RedisUtil.getValue(this.lockKey))){
            RedisUtil.delValue(this.lockKey);
            return true;
        }else{
            logger.warn("锁异常,无法释放,lockKey:"+this.lockKey);
            return false;
        }
    }

}
